﻿//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    Crolengi, this program (a part of program) is gameengine based on C++\Directx
//    Copyright (C) 2008 Pashinin Anton Alekseevich (Crol)
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//    (INCLUDING NEGLIGENCE OR OTHERWISE) 
//    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//    EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//    Contacts: 
//    Mail: crolengi@gmail.com
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef  Static_CObject_VSM_h
#define  Static_CObject_VSM_h

#include <d3d9.h>
#include <d3dx9.h>

#include "..\\import\\CRLEngi_strings_lib\\CRLEngi_strings.h"
#include "..\\import\\param_trees_lib\\param_trees.h"
#include "object_super_class.h"

#include "include\\Managers\\Effect_Manager.h"
#include "include\\Managers\\Light_Manager.h"

#include "include\\Objects\\Static_CObject.h"

#include "include\\Utils\\defines01.h" 

#include "include\\Utils\\list.h"


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// 
/////   :: КЛАСС СТАТИЧНОГО ОБЪЕКТА :: Расширен возможностью скриптования  VSM - virtual script machine
///// 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Static_CObject_VSM:public Static_CObject{
protected:
	DynamicRow         *ScriptLine;
	//DynamicRow         ScriptLine1;
public:
	// структура скриптовой команды
	struct Command_struct{
	   //имя
	   CRLEngi_string  name;
	   //переданные параметры
	   CRLEngi_string  params;
	   float           x;
	   float           y;
	   float           z;
	   //время рождения
	   long            time_start;
	   //время выполнения
	   long            time_to_end;
	   // дополнительные параметры
	   float           mem1;
	   float           mem2;
	   float           mem3;
	   //началось ли уже выполнение?
	   bool            FirstRun;
       // ??
	   bool            RaiseEvent;
	   CRLEngi_string  EndEvent;
	};
	list CommandStack;

CRLEngi_string  S1,S2;
char  c[512],EndEvent[512];char  p[512];
float x,y,z; int rez,time;float xx1,yy1,zz1,complete_percent;
int time_until_end,time_passed;
CRLEngi_string EEvent;
CRLEngi_string params;
D3DXVECTOR3 vec,vecN;
public:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////   Анализ команд
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   bool    AnalyzeCommand(CRLEngi_string  Command){
	 
	 Command.DivideTwoParameters(&S1,&S2);	
	 S1.HideHoles();
	 if (Command == "     ")
		return false;
	 else{
		//Дана команда вращения, её формат должен быть вида - rotate [x,y,z][время мс]
		// пример : rotate 10,0,0 100000
		if (S1 == "rotate"){


		
		}else 
		if (S1 == "wait"){

			Command_struct *a;
			 a = new Command_struct();
			 //char  c[512];

			 //int time,rez;
			 // char  EndEvent[512];
			 rez = sscanf(Command.getChars(),"%s %d %s",c,&time,EndEvent);

			 if (rez!=3){
				 rez = sscanf(Command.getChars(),"%s %d",c,&time);
				 a->RaiseEvent = false;
			 }
			 else
				 a->RaiseEvent = true;

			 //CRLEngi_string EEvent;
			 EEvent = EndEvent;

			 a->name = c;
			 //a->params = params;
			 a->time_start = Console->GetCurrientTime_mseconds();
			 a->time_to_end = time;
			 a->EndEvent = EEvent;
             CommandStack.Add(a);

			 //CRLEngi_string params;
			 params = "Объекту: ";
			 params += Name;
			 params += " Добавлена команда:";
			 params += Command;

			 Console->AddText(params,3);
             
		}else 
		//Дана команда движения в определенную сторону, её формат должен быть вида - move [x,y,z][время мс]
		// пример : move 10,20,0 100000
		if (S1 == "move"){

			 Command_struct *a;
			 a = new Command_struct();

             //char  c[512];
			 
			 //int time,rez;
			 
			 //char  EndEvent[512];
			 xx1 = 0; yy1 = 0; zz1 = 0; time = 0; rez = 0;
			 if (rez!=6){
				 rez = sscanf(Command.getChars(),"%s %f,%f,%f,%d",c,&xx1,&yy1,&zz1,&time);
				 
				 if (rez!=5){
					 rez = sscanf(Command.getChars(),"%s %f,%f,%f %d",c,&xx1,&yy1,&zz1,&time);
				 }
				 else
					 a->RaiseEvent = false;
			 }
			 else
				a->RaiseEvent = true;

			 //CRLEngi_string params;
			 params="";
			 params+=xx1;
			 params+=",";
			 params+=yy1;
			 params+=",";
			 params+=zz1;

			 //CRLEngi_string EEvent;
			 EEvent = EndEvent;

			 

			 a->name = c;
			 a->params = params;
			 a->time_start = Console->GetCurrientTime_mseconds();
			 a->time_to_end = time;
			 a->EndEvent = EEvent;
             CommandStack.Add(a);

			 params = "Объекту: ";
			 params += Name;
			 params += " Добавлена команда:";
			 params += Command;


			 Console->AddText(params,3);
		
		}else 
		//Дана команда движения в определенную сторону, её формат должен быть вида - move [x,y,z][время мс]
		// пример : move 10,20,0 100000
		if (S1 == "move_to"){


			 Command_struct *a;
			 a = new Command_struct();

             //char  c[512];
			 //char  p[512];
			 //int time,rez;
			 //float xx1,yy1,zz1;
			 //char  EndEvent[512];
			 xx1 = 0; yy1 = 0; zz1 = 0; time = 0; rez = 0;
			 rez = sscanf(Command.getChars(),"%s %f,%f,%f %d %s",c,&xx1,&yy1,&zz1,&time,EndEvent);
			 
			 if (rez!=6){
				 rez = sscanf(Command.getChars(),"%s %f,%f,%f,%d",c,&xx1,&yy1,&zz1,&time);
				 
				 if (rez!=5){
					 rez = sscanf(Command.getChars(),"%s %f,%f,%f %d",c,&xx1,&yy1,&zz1,&time);
				 }
				 else
					 a->RaiseEvent = false;
			 }
			 else
				a->RaiseEvent = true;

			 //CRLEngi_string params;
			 params="";
			 params+=xx1;
			 params+=",";
			 params+=yy1;
			 params+=",";
			 params+=zz1;
			 //CRLEngi_string EEvent;
			 EEvent = EndEvent;
			 //EndEvent = 

			

			 a->name = c;
			 a->params = params;
			 a->time_start = Console->GetCurrientTime_mseconds();
			 a->time_to_end = time;
			 a->mem3 = 0.0;
			 a->mem1=0;
			 a->mem2=0;
			 a->FirstRun=true;
			 a->EndEvent = EEvent;
             CommandStack.Add(a);

			 params = "Объекту: ";
			 params += Name;
			 params += " Добавлена команда:";
			 params += Command;

			 Console->AddText(params,3);
		
		}else
        //Дана команда движения в определенную сторону, её формат должен быть вида - rotate_to [x,y,z][время мс]
		// пример : rotate_to 10,20,0 100000
		if (S1 == "rotate_to"){

			 Command_struct *a;
			 a = new Command_struct();

             //char  c[512];
			 //char  p[512];
			 //int time,rez;
			 //float xx1,yy1,zz1;
			 //char  EndEvent[512];
			 xx1 = 0; yy1 = 0; zz1 = 0; time = 0; rez = 0;
			 rez = sscanf(Command.getChars(),"%s %f,%f,%f %d %s",c,&xx1,&yy1,&zz1,&time,EndEvent);
			 
			 if (rez!=6){
				 rez = sscanf(Command.getChars(),"%s %f,%f,%f,%d",c,&xx1,&yy1,&zz1,&time);
				 
				 if (rez!=5){
					 rez = sscanf(Command.getChars(),"%s %f,%f,%f %d",c,&xx1,&yy1,&zz1,&time);
				 }
				 else
					 a->RaiseEvent = false;
			 }
			 else
				a->RaiseEvent = true;

			 
			 vec.x = xx1;
			 vec.y = yy1;
			 vec.z = zz1;
			 D3DXVec3Normalize(&vecN,&vec);
			 //xx1 = vecN.x;
			 //yy1 = vecN.y;
			 //zz1 = vecN.z;

			 //CRLEngi_string params;
			 params="";
			 params+=xx1;
			 params+=",";
			 params+=yy1;
			 params+=",";
			 params+=zz1;
			 //CRLEngi_string EEvent;
			 EEvent = EndEvent;
			 //EndEvent = 

			

			 a->name = c;
			 a->params = params;
			 a->time_start = Console->GetCurrientTime_mseconds();
			 a->time_to_end = time;
			 a->mem3 = 0.0;
			 a->mem1=0;
			 a->mem2=0;
			 a->FirstRun=true;
			 a->EndEvent = EEvent;
             CommandStack.Add(a);

			 params = "Объекту: ";
			 params += Name;
			 params += " Добавлена команда:";
			 params += Command;

			 Console->AddText(params,3);
		
		}else


		if (S1 == "help"){
			S1 = "Список возможных команд для: ";
			S1 += Name;
			Console->AddText(S1,3);	

			S1 = "move - движение по вектору синт.: move [x,y,z,time]";
			Console->AddText(S1,3);	

			S1 = "move_to - движение до точки  синт.: move_to [x,y,z,time] - движение не стирает любые другие команды идущие ниже";
			Console->AddText(S1,3);			
		
		}else{
		//нет такой команды :(
			 S1 = "У объекта: ";
			 S1 += Name;
			 S1 += " не найден обработчик команды:";
			 S1 += Command;

			 Console->AddText(S1,1);		
		}
		
		return true;
	 }
   }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////   запускает команды из стека
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void run_commands(){
  // прогуляемся по стеку команд
  for(list::Item* I=CommandStack.GetItems(); I!=NULL; I=I->next)
  {
    //надоже, что то нашли, но что?
    Command_struct* obj =(Command_struct*)I->ptr;
//--// может это команда move?
	if(obj->name=="move"){
		float x,y,z;
		 int rez;
	     x = 0; y = 0; z = 0; rez = 0;
		 rez = sscanf((obj->params).getChars(),"%f,%f,%f",&x,&y,&z);
		 //параметры то хоть есть?
		 if (rez){
			 //консоль то поди не видна?
			 if(!Console->visible){
			   //int time_until_end,time_passed;
			   //float complete_percent;
			   time_passed    = Console->GetCurrientTime_mseconds() - obj->time_start;
			   time_until_end = obj->time_to_end - Console->GetCurrientTime_mseconds() - obj->time_start;

			   complete_percent = (float)((time_passed*100)/obj->time_to_end);
			 
		       //Position.x+=x*complete_percent;
			   //Position.y+=y*complete_percent;
			   //Position.z+=z*complete_percent;
			   Position.x+=x;
			   Position.y+=y;
			   Position.z+=z;
			   update_position();
			   if (complete_percent>100){
				   CommandStack.RemoveItem(I);
				   if (obj->RaiseEvent)
					   Console->Lua_SendCommand(&Name,&obj->EndEvent);
			       delete(obj);  obj = NULL;
				   break;
			   }
			 }
		 }

	}else
//--// а может это команда move_to?
    if(obj->name=="move_to"){
		//float x,y,z;
		//int rez;
	     x = 0; y = 0; z = 0; rez = 0;
		 rez = sscanf((obj->params).getChars(),"%f,%f,%f",&x,&y,&z);
		 //параметры то хоть есть?
		 if (rez){
			 //консоль то поди не видна?
			 if(!Console->visible){
			  // int time_until_end,time_passed;
			  // float complete_percent,length;
			   //и сколь времени прошло уже?
			   time_passed    = Console->GetCurrientTime_mseconds() - obj->time_start;
			   // а осталось?
			   time_until_end = obj->time_to_end - (Console->GetCurrientTime_mseconds() - obj->time_start);
               // посчитаем ка процент выполнения
			   complete_percent = (float)((float)(time_passed*100)/(float)(obj->time_to_end)); 
               // первый запуск события?
			   if(obj->FirstRun){
				   obj->FirstRun =false;
				   obj->mem1 = Position.x;
				   obj->mem2 = Position.y;
				   obj->mem3 = Position.z;			   
			   }

		       // есть куча времени и можно двигать?
			   if ((time_until_end>0)&&(complete_percent<100)){
			        Position.x=(float)((x*complete_percent)/100)+(float)((obj->mem1 * (100 - complete_percent))/100);
			        Position.y=(float)((y*complete_percent)/100)+(float)((obj->mem2 * (100 - complete_percent))/100);
			        Position.z=(float)((z*complete_percent)/100)+(float)((obj->mem3 * (100 - complete_percent))/100);
			   }else{
			   // ну раз так то сразу телепортируем				   
					   Position.x=x;
					   Position.y=y;
					   Position.z=z;			   
			   }
			   // заставим модель сместить свою тушу на новые координаты
			   update_position();
			   // событие закончилось?
			   if (complete_percent>100){
				   //ну удаляем его нафиг
				   CommandStack.RemoveItem(I);
				   if (obj->RaiseEvent)
					   Console->Lua_SendCommand(&Name,&obj->EndEvent);
				   delete(obj);  obj = NULL;
				   break;
			   }
			 }
		 }

	}else
//--// а может это команда rotate_to?
    if(obj->name=="rotate_to"){
		//float x,y,z;
		//int rez;
	     x = 0; y = 0; z = 0; rez = 0;
		 rez = sscanf((obj->params).getChars(),"%f,%f,%f",&x,&y,&z);
		 //параметры то хоть есть?
		 if (rez){
			 //консоль то поди не видна?
			 if(!Console->visible){
			 //  int time_until_end,time_passed;
			 //  float complete_percent,length;
			   //и сколь времени прошло уже?
			   time_passed    = Console->GetCurrientTime_mseconds() - obj->time_start;
			   // а осталось?
			   time_until_end = obj->time_to_end - (Console->GetCurrientTime_mseconds() - obj->time_start);
               // посчитаем ка процент выполнения
			   complete_percent = (float)((float)(time_passed*100)/(float)(obj->time_to_end)); 
               // первый запуск события?
			   if(obj->FirstRun){
				   obj->FirstRun =false;
				//   D3DXVECTOR3 vec,vecN;
			         vec.x = Rotation.x;
			         vec.y = Rotation.y;
			         vec.z = Rotation.z;
			       D3DXVec3Normalize(&vecN,&vec);
			         Rotation.x = vecN.x;
			         Rotation.y = vecN.y;
			         Rotation.z = vecN.z;
				   obj->mem1 = Rotation.x;
				   obj->mem2 = Rotation.y;
				   obj->mem3 = Rotation.z;			   
			   }

		       // есть куча времени и можно двигать?
			   if ((time_until_end>0)&&(complete_percent<100)){
			        Rotation.x=(float)((x*complete_percent)/100)+(float)((obj->mem1 * (100 - complete_percent))/100);
			        Rotation.y=(float)((y*complete_percent)/100)+(float)((obj->mem2 * (100 - complete_percent))/100);
			        Rotation.z=(float)((z*complete_percent)/100)+(float)((obj->mem3 * (100 - complete_percent))/100);
			   }else{
			   // ну раз так то сразу телепортируем				   
					   Rotation.x=x;
					   Rotation.y=y;
					   Rotation.z=z;			   
			   }
			   // заставим модель сместить свою тушу на новые координаты
			   update_position();
			   // событие закончилось?
			   if (complete_percent>100){
				   //ну удаляем его нафиг
				   CommandStack.RemoveItem(I);
				   if (obj->RaiseEvent)
					   Console->Lua_SendCommand(&Name,&obj->EndEvent);
				   delete(obj);  obj = NULL;
				   break;
			   }
			 }
		 }

	}else
	if(obj->name=="wait"){

			 //консоль то поди не видна?
			 if(!Console->visible){
			   
			   //и сколь времени прошло уже?
			   time_passed    = Console->GetCurrientTime_mseconds() - obj->time_start;
			   // а осталось?
			   time_until_end = obj->time_to_end - (Console->GetCurrientTime_mseconds() - obj->time_start);

			   if (time_until_end<1){
				   //ну удаляем его нафиг
				   CommandStack.RemoveItem(I);
				   if (obj->RaiseEvent)
					   Console->Lua_SendCommand(&Name,&obj->EndEvent);
				   delete(obj);  obj = NULL;
				   break;
			   }
			 
			 }
	}
    
		 
  }//--for
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////   инициализация дополнительных параметров
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool InitParameters3(){
   //	ScriptLine1.fresh();
		//int a;
		//a = ScriptLine1.AddToId(0,true,"_ROOT_");
		//ScriptLine1.fresh();
		//ScriptLine1.AddToId(0,true,"_ROOT_");


	            int id    = ObjProperties.iLookId("_LUA_SCRIPT_FILE_");
			    int count = ObjProperties.iCountParams(id) + ObjProperties.iCountKnots(id);
			    if ((id>0)&&(count>0)){
			    
				int id2 = ObjProperties.TopId(id);
				//LPCSTR Lfilename;
				CRLEngi_string  filename;
				filename = (ObjProperties.iLookName(id2));

				Console->Lua_Open_Script(&filename);
				//Lfilename = filename.getChars();

				}

		return true;
}



void MousePick(D3DXVECTOR3 *vPickRayDir,D3DXVECTOR3 *vPickRayOrig){
if (pMesh!=NULL){
	BOOL cool = false;
	float distance = 0;
   
   D3DXIntersect(pMesh,vPickRayOrig,vPickRayDir,&cool,NULL,NULL,NULL,&distance,NULL,NULL);

   if ((cool)&&(distance>0)&&(distance<1000000)){
	   CRLEngi_string command;
	   command = "mouse_pick";
	   Console->Lua_SendCommand(&Name,&command);   
   }
}
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public:
 Static_CObject_VSM(){};
 Static_CObject_VSM(D3DXMATRIXA16*            GMatrix,
		            char*                     FProperties,
			        LPDIRECT3DDEVICE9        *Device,
			        CLREngi_Effect_Manager   *Eff_Manager,
			        CLREngi_Light_Manager    *L_Manager,
		            CLREngi_Console          *Cnsl){ 

		Console=Cnsl;

		GOMatrixDef = *GMatrix;             // получаем мировую матрицу проекции
	    D3DXMatrixIdentity(&GOMatrix);     // обрабатываем созданную матрицу

		CRLEngi_string file;
		file = FProperties;
		ObjProperties.iLoadFromFile(file); //загрузка параметров

		dwNumMaterials= 0 ;
		Position = D3DXVECTOR3(0.0f,0.0f,0.0f);		

		Effect_Manager = Eff_Manager;

		Light_Manager = L_Manager;

		pd3dDevice = Device;

		aEff=NULL;

		g_pTexture_Light_Map = NULL;

		Name =" ";

		ScriptLine = new DynamicRow();
		ScriptLine->fresh();
		ScriptLine->AddToId(0,true,"_ROOT_");

		//Line.fresh();
	//mainID = Line.AddToId(0,"TIME_LINE");DynamicRow         ScriptLine;
		
	
	};

};
#endif 